﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.Hardware;
using Android.Util;

namespace GBU.Services.Pedometer
{
    public class StepDetector : ISensorEventListener
    {
        private const string TAG = "StepDetector";

        private float MLimit = 10;
        private float[] MLastValues = new float[3 * 2];
        float[] MScale = new float[2];
        private float MYOffset;

        float[] MLastDirections = new float[3 * 2];
        private float[][] MLastExtremes = { new float[3 * 2], new float[3 * 2] };
        float[] MLastDiff = new float[3 * 2];
        private int MLastMatch = -1;

        List<IStepListener> MStepListener = new List<IStepListener>();


        public StepDetector()
        {
            int h = 480;// TODO: remove this constant  //貌似是放大系数
            MYOffset = h * 0.5f; //貌似是 Y轴便宜量,为放大系数的二分之一
            MScale[0] = -(h * 0.5f * (1.0f / (SensorManager.StandardGravity * 2))); //貌似对标准重力加速度进行系数放大
            MScale[1] = -(h * 0.5f * (1.0f / (SensorManager.MagneticFieldEarthMax)));//貌似对地球磁场最大值进行系数放大
        }

        /// <summary>
        /// 设置敏感度(加速度感应系数)
        /// </summary>
        /// <param name="sensitivity"></param>
        /// <remarks>常用敏感系数:  1.97  2.96  4.44  6.66  10.00  15.00  22.50  33.75  50.62</remarks>
        public void SetSensitivity(float sensitivity)
        {
            //常用敏感系数:  1.97  2.96  4.44  6.66  10.00  15.00  22.50  33.75  50.62
            MLimit = sensitivity;
        }

        public void AddStepListener(IStepListener listener)
        {
            if (MStepListener.Contains(listener))
            {
                return;
            }
            MStepListener.Add(listener);
        }

        public void RemoveStepListener(IStepListener listener)
        {
            MStepListener.Remove(listener);
        }

        public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
        {
            //throw new NotImplementedException();
        }

        public void OnSensorChanged(SensorEvent e)
        {
            Log.Debug(TAG, "Sensor value Chaged");
            try
            {
                Sensor sensor = e.Sensor;
                if (sensor.Type == SensorType.Orientation)
                {
                    return;
                }
                int j = (sensor.Type == SensorType.Accelerometer) ? 1 : 0;
                float vSum = 0;
                float v = 0;
                if (j == 1)
                {
                    Log.Debug(TAG, "Acc Sensor value Chaged");
                    for (int i = 0; i < 3; i++)
                    {
                        v = MYOffset + e.Values[i]*MScale[j]; //当当前传感器为加速度计时,获取三个轴向的值,并使用重力加速度系数进行放大,并在Y轴方向进行偏移.
                        vSum += v;
                    }

                    //当当前传感器为其他传感器时,例如 磁场传感器
                    int k = 0;
                    v = vSum/3; //因之前是将三个轴向的加速度偏移量叠加,此处将其变换为单一轴向的平均加速度偏移量

                    float direction = (v > MLastValues[k] ? 1 : (v < MLastValues[k] ? -1 : 0));
                    if (direction == -MLastDirections[k])
                    {
                        //当方向变化
                        int extType = (direction > 0 ? 0 : 1); //最大或最小值
                        MLastExtremes[extType][k] = MLastValues[k];
                        float diff = Math.Abs(MLastExtremes[extType][k] - MLastExtremes[1 - extType][k]);
                        if (diff > MLimit)
                        {
                            bool isLargeAsPrevious = diff > (MLastDiff[k]*2/3);
                            bool isPreviousLargeEnough = MLastDiff[k] > (diff/3);
                            bool isNotContra = (MLastMatch != 1 - extType);

                            if (isLargeAsPrevious && isPreviousLargeEnough && isNotContra)
                            {
                                Log.Debug(TAG, "One Step");
                                foreach (var listener in MStepListener)
                                {
                                    listener.OnStep();
                                }
                                MLastMatch = extType;
                            }
                            else
                            {
                                MLastMatch = -1;
                            }
                        }
                        MLastDiff[k] = diff;
                    }
                    MLastDirections[k] = direction;
                    MLastValues[k] = v;
                }
            }
            catch (Exception ex)
            {
                Log.Debug(TAG, ex.Message + "|" + ex.StackTrace);
            }

        }

        public void Dispose()
        {
           // throw new NotImplementedException();
           
        }

        public IntPtr Handle
        {
            get { return new IntPtr(1); }
        }
    }
}
